/*
 * Copyright 2013-2018 Lilinfeng.
 *  
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *  
 *      http://www.apache.org/licenses/LICENSE-2.0
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.doeis.minaserver.packet;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

import java.nio.charset.Charset;
import java.util.List;

import org.apache.log4j.Logger;

import com.doeis.minaserver.packet.Packet.Direction;
import com.doeis.minaserver.packet.Packet.PacketType;
import com.doeis.minaserver.packet.Packet.ProtocolVersion;
import com.doeis.minaserver.packet.Packet.TransType;

/**
 * @author tianbx
 * @date 2015年6月15日
 * @version 1.0
 * 报文解码器，客户端传递过来的数据由这里进行解码，生成基本的Packet对象
 */
public class NettyMessageDecoder 
	extends ByteToMessageDecoder
	{
	
	// 字符集
	private final Charset charset = Charset.forName("UTF-8");
	// 数据包最大byte长度，一个汉字使用UTF-8编码后占三个byte
	private final int prefixLength = 4;
	private static final Logger log = Logger.getLogger(NettyMessageDecoder.class);


	@Override
	protected void decode(ChannelHandlerContext ctx, ByteBuf in,
			List<Object> out) throws Exception {
		
//		MethodLog methodLog = new MethodLog();
//		methodLog.setCreateTime(new Timestamp(System.currentTimeMillis()));
//		methodLog.setId(IDGenerator.uuid());
//		methodLog.setMethod("channelRead");
//		methodLog.setNote("decode");
//		QueueManager queueManager = NettyServer.getInstance().getT(QueueManager.class);
//		if(queueManager!=null){
//			queueManager.sendLog(methodLog);
//		}
		
		
		// 判断是否够一个数据包的数据，如果够，就先处理这些数据
		if (isAvailable(ctx, in)) {
			parserPacket(ctx, in, out);
		}
	}
	
	private void parserPacket(ChannelHandlerContext ctx, ByteBuf msg,
			List<Object> out) {
		try{
			
//			MethodLog methodLog = new MethodLog();
//			methodLog.setCreateTime(new Timestamp(System.currentTimeMillis()));
//			methodLog.setId(IDGenerator.uuid());
//			methodLog.setMethod("channelRead");
//			methodLog.setNote("parserPacket解码开始");
//			QueueManager queueManager = NettyServer.getInstance().getT(QueueManager.class);
//			if(queueManager!=null){
//				queueManager.sendLog(methodLog);
//			}
			
			int length = msg.readInt();//数据包总长度
			//web请求,直接过滤
			if(length == 1195725856){
//				ioSession.close(true);
				return;
			}
			
			if(length == 790644820 ){
				return ;
			}
			
			byte oneByte = msg.readByte();
			PacketType[] enumConstants = PacketType.class.getEnumConstants();
			
			PacketType type = enumConstants[oneByte];
			Packet packet = PacketFactory.basePacket(type);
			packet.setPacketType( type );
			
			oneByte = msg.readByte();
			ProtocolVersion[] protocolVersions = ProtocolVersion.class.getEnumConstants();
			
			packet.setVersion( protocolVersions[oneByte] );
			
			oneByte = msg.readByte();
			Direction[] directions = Direction.class.getEnumConstants();
			
			packet.setDirection( directions[oneByte] );
			packet.setCmd( msg.readByte() );
			packet.setNotifyType( msg.readInt() );
			
			oneByte = msg.readByte();
			TransType[] transTypes = TransType.class.getEnumConstants();
			
			packet.setTransType( transTypes[oneByte] );
			packet.setTime( msg.readLong());
			// 来源id长度
			byte fromLen = msg.readByte();
			// 去向id长度
			byte toLen = msg.readByte();
			// message password len
			byte pwdLen = msg.readByte();
			
			ByteBuf byteBuf = msg.readBytes(fromLen);
			
			String from = new String(byteBuf.array(), charset);
			byteBuf = msg.readBytes(toLen);
			String to = new String(byteBuf.array(), charset);
			byteBuf = msg.readBytes(pwdLen);
			String pwd = new String(byteBuf.array(), charset);
			packet.setFrom(from);		
			packet.setTo(to);
			packet.setPwd(pwd);
			
			// 读取报文内容的长度
			int contentSize = length - fromLen - toLen - pwdLen - Packet.packetHeaderLength;
			byteBuf = msg.readBytes(contentSize);
			String content = new String(byteBuf.array(), charset);
			packet.setBody( content );
			// 向上层传递正式的包
			out.add(packet);
	
			
//			methodLog = new MethodLog();
//			methodLog.setCreateTime(new Timestamp(System.currentTimeMillis()));
//			methodLog.setId(IDGenerator.uuid());
//			methodLog.setMethod("channelRead");
//			methodLog.setNote("parserPacket解码结束");
//			if(queueManager!=null){
//				queueManager.sendLog(methodLog);
//			}
			
			// 看看下面的数据是否还能成为一个数据包，
			if ( isAvailable(ctx, msg) ) {
				parserPacket(ctx, msg, out);
			} 
		}catch (Exception e) {
			log.error("ParserPacket Error", e);
//			throw e;
		}
	}

	private boolean isAvailable(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
		int windex = msg.writerIndex();
		int rindex = msg.readerIndex();
		
		int remainingLen = windex - rindex;
		

		if (remainingLen < prefixLength) {
			return false;
		}
		
		int dataLength = msg.getInt(rindex);
		
		//过滤web请求
		if(dataLength == 1195725856){
			return true;
		}
		if(dataLength == 790644820){
			return true;
		}
		
			
//		System.out.println("dataLength:"+dataLength+" remainingLen:"+remainingLen);
		if (dataLength < 0 || dataLength > NettyMessageEncoder.maxDataLength) {
			throw new Exception("解码时,数据包长度超出协议充许的范围:0<x<"+NettyMessageEncoder.maxDataLength+", x=" + dataLength+", ip="+ctx.channel().remoteAddress().toString());
		}
		return remainingLen >= dataLength;
	}



    
}
